// Define a function.
import 'package:flutter/widgets.dart';

void printInteger(int number){
  print("the number is $number"); // Print to console.
}

// This is where the app starts executing.
void main(){
  var number = 42;  // Declare and initialize a variable.
  // assert(lineCount != null);
  printInteger(number);   // Call a function.
}

/*===================变量======================*/

// var 关键字声明的变量仅存储对象的引用
var name = 'Bob';

// dynamic 关键字声明的变量类型可变
dynamic name2 = 'Bob';

/*===================默认值======================*/

// 在 Dart 中，未初始化的变量拥有一个默认的初始化值：null。即便数字也是如此，因为在 Dart 中一切皆为对象，数字也不例外。
int? lineCount;

/*=================== final 和 const ======================*/

final name3 = 'Bob';  //Without a type annotation
final String nickName = 'Bobby';

const bar  = 10000; //
const double atm = 1.01325 * bar; // 利用其他 const 变量赋值

void modifyVal(){
  // You cant't modify a final variable
  //name3 = "Alice";
}

// const 关键字不仅仅可以用来定义常量，还可以用来创建 常量值，该常量值可以赋予给任何变量
var foo = const[];
final bar2 = const[];
const baz = []; // 相当于 const[]

// 没有使用 final 或 const 修饰的变量的值是可以被更改的，即使这些变量之前引用过 const 的值
void modifyVal2(){
  foo = [1,2,3];  // foo 的值之前为 const[]
  //baz = [42]  ; // 报错：常量值不可以被赋值。
}

// 你可以在常量中使用 类型检查和强制类型转换 (is 和 as)、 集合中的 if 以及 展开操作符 (... 和 ...?)
const Object i = 3; // Where i is a const Object with an int value...
const list = [i as int]; //Use a typecast.
const map = {if (i is int) i: 'int'}; // Use is and collection if.
const set = {if (list is List<int>) ...list}; // ...and a spread.


/*=================== 内置类型 ======================*/

// Dart 支持以下的8种类型：
/*
 * 1. numbers(int, double)
 * 2. strings
 * 3. booleans
 * 4. lists
 * 5. sets
 * 6. maps
 * 7. runes
 * 8. symbols
 */

// 1. Numbers

var x = 1;
var hex = 0xDEADBEEF;

var y = 1.1;
var exponents = 1.42e5;

// Notes：在 Dart 2.1 之前，在浮点数上下文中使用整数字面量是错误的。
double z = 1; // Equivalent to double z = 1.0;


// Turn a string into a number, or vice versa.
void turn(){
  // String -> int
  var one  = int.parse('1');
  assert(one == 1);

  // String -> double
  var onePointOne = double.parse('1.1');
  assert(onePointOne == 1.1);

  // int -> String
  String oneAsString = 1.toString();
  assert(oneAsString == '1');

  // double -> String
  String piAsString = 3.14159.toStringAsFixed(2);
  assert(piAsString == '3.14');

  assert((3 << 1) == 6);  // 0011 << 1 == 0110
  assert((3 >> 1) == 1);  // 0011 >> 1 == 0001
  assert((3 | 4) == 7);  // 0011 | 0100 == 0111
}


// 2. Strings


// 3. Booleans



// 4. Lists

var list2 = [1, 2, 3];
var list3 = [
  'Car',
  'Boat',
  'Plane',
];

void listOpt(){
  assert(list2.length == 3);
  assert(list2[1] == 2);

  list2[1] = 1;
  assert(list2[1] == 1);
}

// Dart 在 2.3 引入了 扩展操作符（...）和 空感知扩展操作符（...?），它们提供了一种将多个元素插入集合的简洁方法。
var list4 = [0,...list2];

// 5. Sets

var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};


// 6. Maps
var gifts = {
  // 键:    值
  'first': 'partridge',
  'second': 'turtledoves',
  'fifth': 'golden rings'
};

// 7. Runes


// 8. Symbols

/*============================= 函数 ==============================================*/

// Dart 是一种真正面向对象的语言，所以即便函数也是对象并且类型为 Function，
// 这意味着函数可以被赋值给变量或者作为其它函数的参数。你也可以像调用函数一样调用 Dart 类的实例。

bool isNoble(int atomicNumber){
  //return _nobleGases[atomicNumber] != null;
  return atomicNumber == 3;
}

//bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;

// 函数可以有两种形式的参数：必要参数 和 可选参数。必要参数定义在参数列表前面，可选参数则定义在必要参数后面。可选参数可以是 命名的 或 位置的。

void enableFlags({bool? bold, bool? hidden}){}  // enableFlags(bold: true, hidden: false);

Scrollbar({Key? key, required Widget child}){}

String say(String from, String msg, [String device = 'carrier pigeon']){
  return "hello";
}

// 可以将函数作为参数传递给另一个函数。例如
void printElem(int element){
  print(element);
}

var list5 = [1, 2, 3];
// list5.forEach(printElem);

// 你也可以将函数赋值给一个变量，比如：
var loudify = (msg) => '!!! ${msg.toUpperCase()} !!!';
// assert(loudify('hello') == '!!! HELLO !!!');

// 匿名函数
// 大多数方法都是有名字的，比如 main() 或 printElement()。你可以创建一个没有名字的方法，
// 称之为 匿名函数、 Lambda表达式 或 Closure闭包。你可以将匿名方法赋值给一个变量然后使用它，比如将该变量添加到集合或从中删除。
var list6 = ['apples', 'bananas', 'oranges'];
// list.forEach((element) { print('${list.indexOf(item)}: $item'); });



/*============================= 类 ==============================================*/

class Point {
  double? x, y;

  Point(this.x, this.y);

  // 命名式构造函数
  Point.origin()
      : x=0,
        y=0;

  // 使用初始化列表在构造函数体执行前设置实例变量。
  Point.fromJson(Map<String, double> json) : x = json['x'], y = json['y'] {
      print('In Point.fromJson(): ($x, $y)');
  }
}

class Person {
  String? firstName;

  Person.fromJson(Map data) {
    print('in Person');
  }
}

class Employee extends Person {
  // Person does not have a default constructor;
  // you must call super.fromJson(data).
  Employee.fromJson(Map data) : super.fromJson(data) {
    print('in Employee');
  }
}

// 抽象类


// 隐式接口


/*============================= 异步支持 ==============================================*/

Future<String> login(String userName, String pwd){
  // 用户登录
  return Future((){
    return "aa";
  });
}

/// 声明了 async 的函数, 返回值必须是 Future 对象,即使你在 async 函数内直接返回 T 类型数据,
/// 编译器会自动帮你包装成 Future<T> 对象。在遇到 await 时候, 又会把 Future 类型拆包
Future<String> getUserInfo (String id) async {
  // 获取用户信息
  var res = await Future.delayed(Duration(seconds: 3), (){
    return "bb";
  });
  return "aa$res";
}

Future<void> saveUserInfo(String userInfo){
  // 保存用户信息
  return Future((){

  });
}

void task1() {
  login("userName", "pwd").then((id){
    getUserInfo(id).then((userInfo){
      saveUserInfo(userInfo).then((val){
      });
    });
  });
}

void task2(){
  login("userName", "pwd").then((id){
    return getUserInfo(id);
  }).then((userInfo){
    return saveUserInfo(userInfo);
  }).then((e){
    // 执行接下来的操作
  }).catchError((e){
    // 错误处理
  });
}

void task3() async{
  try{
    String id = await login("userName", "********");
    String userInfo = await getUserInfo(id);
    await saveUserInfo(userInfo);
  } catch(e){
    print(e);
  }
}

void task4(){
  Stream.fromFutures([
    // 1s 后返回结果
    Future.delayed(new Duration(seconds: 1), (){
    return "Hello 1";
    }),
    // 抛出一个异常
    Future.delayed(new Duration(seconds: 2), (){
    throw AssertionError("Error");
    }),
    // 3s 后返回结果
    Future.delayed(new Duration(seconds: 3), (){
    return "hello 3";
    })
  ]).listen((data) {
    print(data);
  },onError: (e){
    print(e.message);
  },onDone: (){

  });
}





